#include <stdio.h>
#include <event.h>
#include <event2/event.h>
#include <event2/bufferevent.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>

#include "bike.pb.h"
//#include "ngx_mem_pool.h"
#include <string.h>
#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
#include <chrono>
#define MAXLEN 1024
using namespace tutorial;

typedef struct _Conn Conn;
typedef struct _ConnectStat ConnectStat;

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef signed char i8;
typedef signed short i16;
typedef signed int i32;
typedef float r32;
typedef double r64;
typedef long double r128;
const int num = 9500;
static int wr_count = 0;
//char *msg = NULL;
struct _Conn{
    evutil_socket_t InitClientConnect(short port, const char *ip_addr){
        evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, 0), ret = -1;
        if(-1 == sock){
            printf("client sock create failure\n");
            return ret;
        }
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = inet_addr(ip_addr);

        ret = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
        if(-1 == ret){
            perror("client sock connect failure\n");
            return ret;
        }

        return sock;
    }
};

/*typedef struct _ConnStat Connstat;
struct _ConnStat{
    ngx_mem_pool *_pool; 
};*/


// 记录压测指标
std::atomic<size_t> success_count{0};
std::atomic<size_t> total_count{0};
std::atomic<long long> total_response_time{0};
// 封装客户端连接逻辑（可复用）
class PressureTestClient {
public:
    void init(int port, const char* ip) {
        base = event_base_new();
        if (!base) {
            std::cerr << "create event base failure" << std::endl;
            return;
        }
        sock = conn.InitClientConnect(port, ip);
        if (-1 == sock) {
            std::cerr << "connect server failure" << std::endl;
            return;
        }

        bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE);
        if (!bev) {
            perror("create buffer event failure");
            return;
        }
        
        bufferevent_setcb(bev, nullptr, writeCallback, eventcb, this);
        bufferevent_enable(bev, EV_WRITE | EV_PERSIST);
    }

    void run() {
        if (base) {
            event_base_dispatch(base);
        }
    } 

    ~PressureTestClient() {
        if (bev) {
            bufferevent_free(bev);
        }
        if (base) {
            event_base_free(base);
        }
    }

private:
    static std::chrono::time_point<std::chrono::steady_clock> start;
    // 发送回调（复用原逻辑）
    static void writeCallback(struct bufferevent* bev, void* ctx) {
        //PressureTestClient* client = static_cast<PressureTestClient*>(ctx);
        //start = std::chrono::steady_clock::now();
        // 构造请求数据（复用原逻辑）
        //char msg[1024] = "\0";
        char *msg = NULL;
        msg = (char*)::operator new(sizeof(char) * 128);
        mobile_request mrq;
        mrq.set_mobile("18136728538");
        int len = mrq.ByteSize();

        memcpy(msg, "FBEB", 4);
        *(u16*)(msg + 4) = 1;
        *(u32*)(msg + 6) = len;
        mrq.SerializeToArray(msg + 10, len);

        size_t nwrite = bufferevent_write(bev, msg, len + 10);
        total_count++;
        //if (nwrite == len + 10) {
          //  success_count++;
        //}
        if(msg){
            msg = NULL;
            delete [] msg;
	}
        
        wr_count ++;
        
//        printf("write count = %d\n", wr_count);
        bufferevent_setcb(bev, readCallback, nullptr, eventcb, nullptr);

        bufferevent_enable(bev, EV_READ | EV_PERSIST);

    }

    // 事件回调（复用原逻辑）
    static void eventcb(struct bufferevent* bev, short events, void* ctx) {
        if(events & BEV_EVENT_EOF){
            printf("server connect close\n");
            //bufferevent_free(bev);
            printf("write count = %d\n", wr_count);
        }
        return;
    }
   
    static void readCallback(struct bufferevent *bev, void *ctx){
       // auto end = std::chrono::steady_clock::now();
       // auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
        //total_response_time += duration; // 累加响应时间
        //std::cout << "Now Total response time ---> " << total_response_time << " ms" << std::endl;
        //char msg[1024] = "\0";
        char *msg = NULL;
        msg = (char*)::operator new(sizeof(char) * 128);
        size_t nread = bufferevent_read(bev, msg, MAXLEN);

        std::cout << "read len from server <<<< " << nread << std::endl;

        std::cout << "read msg from server <<<< " << msg << std::endl;
          

        u32 len = 0;

        if(strncmp(msg, "FBEB", 4) == 0){
           u16 id = *(u16*)(msg + 4);
           len = *(u32*)(msg + 6);
        }  

        std::cout << "read msg len from server <<<<< " << len << std::endl;

        //std::cout << "read msg from server <<<< " << msg + 10 << std::endl;
     	mobile_response mrp;
     	mrp.ParseFromArray(msg + 10, len);
    	auto code = mrp.code();
     	auto icode = mrp.icode();
     	auto desc = mrp.desc();
        
     	printf("recv data from server<<<< code:%d, desc:%s, icode:%d\n", code, desc.data(), icode);
        
        if(msg){
            msg = NULL;
            delete [] msg;
        }
    }
    struct event_base* base{nullptr};
    struct bufferevent* bev{nullptr};
    evutil_socket_t sock{-1};
    // 假设原有的连接类
    Conn conn;
};
std::chrono::time_point<std::chrono::steady_clock> PressureTestClient::start;
int main(int argc, char** argv) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " <port> <ip>" << std::endl;
        return 1;
    }

    const int thread_num = num; // 模拟10000并发
    const int port = atoi(argv[1]);
    const char* ip = argv[2];

    std::vector<std::thread> threads;
    threads.reserve(thread_num);
    
    //auto now = std::chrono::steady_clock();
    //auto start = std::chrono::steady_clock::now();

    for (int i = 0; i < thread_num; ++i) {
        threads.emplace_back([port, ip]() {
            PressureTestClient client;
            client.init(port, ip);
            client.run();
        });
    }

    for (auto& th : threads) {
        if (th.joinable()) {
            th.join();
        }
    }
    //auto end = std::chrono::steady_clock::now();

    //auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
 
    //std::cout << "time: " << diff << "ms" << std::endl; 
    // 输出压测结果
     //std::cout << "Total requests: " << total_count << std::endl;
     //std::cout << "Total response time: " << total_response_time << " us" << std::endl;
//   std::cout << "Success requests: " << success_count << std::endl;
//    std::cout << "Success rate: " << static_cast<double>(success_count) / total_count * 100 << "%" << std::endl;

    return 0;
}

